<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      #btnGroup {
        display: flex;
        align-items: center;
        justify-content: center;
      }
      #btnGroup > button {
        margin-right: 10px;
      }
      #editor {
        border: 1px solid;
        width: 840px;
        margin: 0 auto;
        box-sizing: border-box;
        padding: 0 20px;
        background: #ffffff;
        margin-top: 20px;
        position: relative;
        min-height: calc(100vh - 190px);
      }
      .editorContainer {
        outline: none;
      }
      .public-root {
        color: #8590a6;
        position: absolute;
        pointer-events: none;
      }

      .public-pre {
        border-radius: 4px;
      }

      pre {
        margin: 1.4em 0;
        padding: 0.88889em;
        font-size: 0.9em;
        word-break: normal;
        word-wrap: normal;
        white-space: pre;
        overflow: auto;
        -webkit-overflow-scrolling: touch;
        background: #f6f6f6;
        border-radius: 4px;
      }
    </style>
  </head>
  <body>
    <div id="btnGroup">
      <button id="undo">撤销</button>
      <button id="redo">恢复</button>
      <button id="bold">加粗</button>
      <button id="italic">倾斜</button>
      <button id="underline">下划线</button>
      <button id="strikeThrough">删除线</button>
      <button id="h1">H1</button>
      <button id="h2">H2</button>
      <button id="h3">H3</button>
      <button id="foreColor">字体颜色</button>
      <button id="hiliteColor">字体背景</button>
      <button id="insertOrderedList">有序</button>
      <button id="insertUnorderedList">无序</button>
      <button id="insertImage">插入图片</button>
      <button id="code-block">代码块</button>
    </div>
    <div id="editor">
      <div class="public-root">请输入文章正文...</div>
      <div class="editorContainer" contenteditable></div>
    </div>
    <script>
      let value = '';
      window.onload = function () {
        const btnGroup = document.getElementById('btnGroup');
        const editor = document.getElementById('editor');
        const editorContainer = editor.querySelector('.editorContainer');
        editor.addEventListener('click', function () {
          // editorContainer.focus();
          keepLastIndex(editorContainer);
        });
        editorContainer.addEventListener('click', function (e) {
          e.stopPropagation();
        });
        editorContainer.addEventListener('input', function (e) {
          // console.log(e);
          const show = document.queryCommandState('bold');

          show
            ? (document.getElementById('bold').style = 'color:red;')
            : (document.getElementById('bold').style = 'color:;');

          const p = document.querySelector('.public-root');
          if (!p) return;
          p.remove();
        });
        document.onkeydown = function (e) {
          var keyCode = e.keyCode || e.which || e.charCode;
          var ctrlKey = e.ctrlKey;
          if (ctrlKey && keyCode == 66) {
            const show = document.queryCommandState('bold');
            !show
              ? (document.getElementById('bold').style = 'color:red;')
              : (document.getElementById('bold').style = 'color:;');
          }
        };
        btnGroup.addEventListener('click', function (e) {
          const id = e.target.id;
          editorContainer.focus();
          switch (id) {
            case 'bold':
              bold();
              const show = document.queryCommandState('bold');
              show
                ? (e.target.style = 'color:red;')
                : (e.target.style = 'color:;');

              break;
            case 'undo':
              undo();
              break;
            case 'redo':
              redo();
              break;

            case 'italic':
              italic();
              break;
            case 'underline':
              underline();
              break;
            case 'strikeThrough':
              strikeThrough();
              break;
            case 'h1':
              h1();
              break;
            case 'h2':
              h2();
              break;
            case 'h3':
              h3();
              break;
            case 'foreColor':
              foreColor();
              break;
            case 'hiliteColor':
              hiliteColor();
              break;
            case 'insertOrderedList':
              insertOrderedList();
              break;
            case 'insertUnorderedList':
              insertUnorderedList();
              break;
            case 'insertImage':
              insertImage();
              break;
            case 'code-block':
              codeBlock();
              break;
            default:
              break;
          }
        });
        const codeBlock = () => {
          document.execCommand(
            'insertHTML',
            false,
            `
          
          <pre class="public-pre">
          
            </pre>
          
          `
          );
        };
        // 加粗
        const bold = () => {
          document.execCommand('bold', false, null);
        };

        const undo = () => {
          document.execCommand('undo', false, null);
        };

        const redo = () => {
          document.execCommand('redo', false, null);
        };

        // 斜体
        let italic = () => {
          document.execCommand('italic', false, null);
        };

        // 下划线
        let underline = () => {
          document.execCommand('underline', false, null);
        };

        // 删除线
        let strikeThrough = () => {
          document.execCommand('strikeThrough', false, null);
        };

        // H1
        let h1 = () => {
          document.execCommand('fontSize', false, 7);
        };

        // H2
        let h2 = () => {
          document.execCommand('fontSize', false, 6);
        };

        // H3
        let h3 = () => {
          document.execCommand('fontSize', false, 5);
        };

        // 字体颜色
        let foreColor = () => {
          document.execCommand('foreColor', false, 'red');
        };

        // 字体背景
        let hiliteColor = () => {
          document.execCommand('hiliteColor', false, 'yellow');
        };

        // 有序列表
        let insertOrderedList = () => {
          document.execCommand('insertOrderedList', false, null);
        };

        // 无序列表
        let insertUnorderedList = () => {
          document.execCommand('insertUnorderedList', false, null);
        };

        const insertImage = () => {
          document.execCommand(
            'insertImage',
            false,
            'https://profile-avatar.csdnimg.cn/f156c8c86365491594ffc1dbdef56d91_qq_25833731.jpg!3'
          );
        };

        function keepLastIndex(obj) {
          if (window.getSelection) {
            //ie11 10 9 ff safari
            obj.focus(); //解决ff不获取焦点无法定位问题
            var range = window.getSelection(); //创建range
            range.selectAllChildren(obj); //range 选择obj下所有子内容
            range.collapseToEnd(); //光标移至最后
          } else if (document.selection) {
            //ie10 9 8 7 6 5
            var range = document.selection.createRange(); //创建选择对象
            //var range = document.body.createTextRange();
            range.moveToElementText(obj); //range定位到obj
            range.collapse(false); //光标移至最后
            range.select();
          }
        }
      };
    </script>
    <script>
      // http://eux.baidu.com/blog/fe/%e5%88%a9%e7%94%a8-javascript-%e5%ae%9e%e7%8e%b0%e5%af%8c%e6%96%87%e6%9c%ac%e7%bc%96%e8%be%91%e5%99%a8
      // mdn https://developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand
    </script>
  </body>
</html>
